#!/usr/bin/python
#-*- coding:utf-8 -*-

import urllib.request
import urllib.parse
import html.parser
import os.path
import re
import sys

def search_song():
    kw = input('Singer name: ').strip()

    if kw == '':
        print('Bye')
        return ''

    kw = urllib.parse.quote(kw)

    start = 0
    url = 'http://www.google.cn/music/search?q={0}&cat=song&start={1}'

    ids = []
    names = []

    print('Searching songs .', end = '')
    sys.stdout.flush()

    page = urllib.request.urlopen(url.format(kw, start)).read().decode('utf-8')

    res = re.findall(r'<b>(\d+)</b> - <b>(\d+)</b>', page)
    beg, end = res[0] if res != [] else (1, 0)

    # fetch all search results
    while int(beg) <= int(end):
        # fetch song ids and names
        ids += re.findall(r'<tbody id="(.*?)"', page)
        names += re.findall(r'(?s)<input type="checkbox"(?:.*?)<a href="(?:.*?) onclick=(?:.*?)">(.*?)</a>', page)

        start = end
        print('.', end = '')
        sys.stdout.flush()

        page = urllib.request.urlopen(url.format(kw, start)).read().decode('utf-8')

        res = re.findall(r'<b>(\d+)</b> - <b>(\d+)</b>', page)
        beg, end = res[0] if res != [] else (1, 0)

    if names == []:
        print('\nNo songs found, bye')
        return ''

    # show result
    print()
    for song in enumerate(zip(ids, names)):
        print("{0}{1}".format(str(song[0] + 1).ljust(10), re.sub(r'(\n|<[/\w]+>)', '', song[1][1])))

    # choose a number to download
    while True:
        song_no = input('\nChoose a song: ')
        try:
            print('Chosen:', ids[int(song_no) - 1])
            song_no = int(song_no)
        except ValueError:
            print('Oops, try again')
        except IndexError:
            print('Oops, try again')
        else:
            break

    return ids[int(song_no) - 1]

def download_song(song_id):
    if song_id == '':
        return

    parser = html.parser.HTMLParser()

    # request for the iframe
    url = 'http://www.google.cn/music/top100/musicdownload?id={0}'
    req = urllib.request.Request(url.format(song_id))

    # necessary?
    req.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; ' \
                                 'Windows NT 6.0; en-US; rv:1.8.1.7) ' \
                                 'Gecko/20070914 Firefox/2.0.0.7')

    # request for the mp3 file
    page = urllib.request.urlopen(req).read().decode('utf-8')
    link = re.search(r'<a href="(/music/top100/url(?:[^>]*?))">', page).group(1)
    req = urllib.request.Request('http://www.google.cn' + parser.unescape(link))

    while True:
        print('Downloading ...')

        resp = urllib.request.urlopen(req)

        default_name = urllib.parse.unquote(re.search(r'.*/(.*)$', resp.geturl()).group(1))

        folder = input('Save the song to [default is ./{0}]: '.format(default_name)).strip()

        try:
            # nothing typed
            folder = '.' if folder == '' else folder

            # no filename typed
            folder += ('/' + default_name) if os.path.isdir(folder) else ''

            out_file = open(re.sub(r'/+', '/', folder), 'wb')

            print('Writing file ...')

            out_file.write(resp.read())
        except IOError:
            print('Oops, invalid path, try again')
        except Exception:
            print('..... try again')
        else:
            break

    out_file.close()
    return

if __name__ == '__main__':
    download_song(search_song())
